/*
 * Window.cpp
 *
 *  Created on: 09.06.2010
 *      Author: skuld
 */

#include <windows.h>
#include <sstream>

#include "SDL/SDL_image.h"
#include "Window.h"
#include "GUI.h"

GUI gui;

/*
 * Constructor
 * Sets up screen attributes, pointers, colors, etc etc.
 */
Window::Window()
{
	// Set pointers to NULL
	screen = NULL;
	background = NULL;
	scoreLabel = NULL;
	scoreDisplay = NULL;
	font = NULL;
	blocks = NULL;

	// Set necessary attributes

}

// FOR FUCK'S SAKE, USE REFERENCES WHEN WRITING GET FUNCTIONS
GUI& Window::getGUI() {
	return gui;
}

/*
 * Custom flip function, flips the screen and handles errors.
 */
void Window::flipScreen()
{
	if(SDL_Flip(screen) == -1)
		{
			MessageBox(0, "Failed to flip screen", NULL, MB_ICONHAND);
		}
}

/*
 * Image loading function
 * Takes a path/filename as its argument, optimizes the image (converts it
 * to the same bpp as the screen), sets a color key (cyan) and then returns
 * a pointer to the optimized image.
 */
SDL_Surface* Window::load_image(std::string filename)
{
	// The image that's loaded
	SDL_Surface* loadedImage = NULL;

	// Optimized image that will be used
	SDL_Surface* optimizedImage = NULL;

	// Load the image
	loadedImage = IMG_Load(filename.c_str());

	// If successful
	if(loadedImage != NULL)
	{
		// create an optimized image
		optimizedImage = SDL_DisplayFormat(loadedImage);

		// Free the old image
		SDL_FreeSurface(loadedImage);
	}

	// Color keying
	if(optimizedImage != NULL)
	{
		// Map the color key
		Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF);

		// Set all pixels of color 0, 0xFF, 0xFF (cyan) to be transparent
		SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
	}

	// Return the optimized image
	return optimizedImage;
}

/*
 * Blitting function
 * Blits an image onto a destination with a given offset.
 *
 * Clipping is also possible (default = NULL, so calling
 * apply_surface(x, y, source, destination) and
 * apply_surface(x, y, source, destination, NULL do the same thing).
 */
void Window::apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL)
{
	// Temporary rectangle to hold the offsets
	SDL_Rect offset;

	// Get the offsets
	offset.x = x;
	offset.y = y;

	// Blit the surface
	SDL_BlitSurface(source, clip, destination, &offset);
}

/*
 * Initialization function
 * Initializes SDL, the screen and the window caption.
 */
bool Window::init()
{
	// Initialize SDL
	if(SDL_Init(SDL_INIT_EVERYTHING) == -1)
	{
		MessageBox(0, "SDL Initialization failed.", NULL, MB_ICONHAND);
		return false;
	}

	// Initialize SDL TTF
	if(TTF_Init() == -1)
	{
		MessageBox(0, "Failed to set up TTF.", NULL, MB_ICONHAND);
		return false;
	}

	// set up the screen
	screen = SDL_SetVideoMode(800, 600, 32, SDL_SWSURFACE);

	if(screen == NULL)
	{
		MessageBox(0, "Failed to set up screen.", NULL, MB_ICONHAND);
		return false;
	}

	// set window caption
	SDL_WM_SetCaption("Bishi Blocks", NULL);

	// set dimensions of the GUI Background
	guiBG.x = 450;
	guiBG.y = 0;
	guiBG.w = 350;
	guiBG.h = 600;

	// if everything went well
	return true;
}

/*
 * Loads up necessary data like fonts and static surfaces.
 */
bool Window::load()
{
	// Load font
	font = TTF_OpenFont("lazy.ttf", 28);

	if(font == NULL)
	{
		MessageBox(0, "Failed to load font.", NULL, MB_ICONHAND);
		return false;
	}

	// Text color to white
	SDL_Color textColor = {255, 255, 255};

	// Load non-changing GUI members
	scoreLabel = TTF_RenderText_Solid(font, "Score", textColor);

	if(scoreLabel == NULL)
	{
		MessageBox(0, "Failed to load GUI.", NULL, MB_ICONHAND);
		return false;
	}

	// Load the block sprite sheet
	blocks = load_image("img/blocks.png");

	// Set clipping size for blocks
	// Long Block
	clip[0].x = 0;
	clip[0].y = 0;
	clip[0].w = 180;
	clip[0].h = 45;

	// Inverted L-Block
	clip[1].x = 180;
	clip[1].y = 0;
	clip[1].w = 135;
	clip[1].h = 90;

	// L-Block
	clip[2].x = 315;
	clip[2].y = 0;
	clip[2].w = 135;
	clip[2].h = 90;

	// Square
	clip[3].x = 0;
	clip[3].y = 90;
	clip[3].w = 90;
	clip[3].h = 90;

	// T-Block
	clip[4].x = 90;
	clip[4].y = 90;
	clip[4].w = 135;
	clip[4].h = 90;

	// Z-Block
	clip[5].x = 225;
	clip[5].y = 90;
	clip[5].w = 135;
	clip[5].h = 90;

	// Inverted Z-Block
	clip[6].x = 360;
	clip[6].y = 90;
	clip[6].w = 135;
	clip[6].h = 90;

	return true;

}

/*
 * Loads up a level, indicated by the levelNr argument.
 */
bool Window::loadLevel(std::string levelNr)
{
	// load the background
	background = load_image("img/level"+levelNr+".png");

	if(background == NULL)
	{
		MessageBox(0, "Failed to load background image.", NULL, MB_ICONHAND);
		return false;
	}

	apply_surface(0, 0, background, screen);

	// Load some blocks
	apply_surface(0, 510, blocks, screen, &clip[4]);
	apply_surface(90, 555, blocks, screen, &clip[0]);
	apply_surface(225, 510, blocks, screen, &clip[6]);
	apply_surface(135, 465, blocks, screen, &clip[3]);
	apply_surface(200, 100, blocks, screen, &clip[2]);

	flipScreen();
	return true;
}

/*
 * Refreshes the GUI.
 * Frees the surfaces first and fills the GUI black.
 * Then gets the updated score data and redraws it.
 */
void Window::refreshGUI()
{
	// used for getting the score from the gui class
	std::string stringScore;
	std::stringstream out;

	// Draw the GUI black so it can be redrawn with the updated score
	SDL_FillRect(screen, &guiBG, 0x000000);


	//GUI gui;
	// Get the updated score
	out << gui.getScore();

	stringScore = out.str();

	const char *score = stringScore.c_str();
	// Display the updated score (and "Score" label)
	SDL_Color textColor = {255, 255, 255};
	scoreDisplay = TTF_RenderText_Solid(font, score, textColor);
	apply_surface(480, 30, scoreDisplay, screen);
	apply_surface(480, 0, scoreLabel, screen);

	flipScreen();

	// Delay so the GUI doesn't flicker
	// TODO: Regulate it with framerate etc.
	SDL_Delay(200);
}

/*
 * Cleans up for program exit.
 */
void Window::cleanUp()
{
	// Free all surfaces
	SDL_FreeSurface(scoreLabel);
	SDL_FreeSurface(scoreDisplay);
	SDL_FreeSurface(background);

	// Quit SDL
	SDL_Quit();
}
